"""
Alpha Manager 
Entidades de la base de datos
"""

import transaction
import cryptacular.bcrypt
from pyramid.security import Allow
from pyramid.security import Everyone
from pyramid.security import Authenticated
from pyramid.security import authenticated_userid
from sqlalchemy.orm import relationship
from sqlalchemy import Table
from sqlalchemy import Column
from sqlalchemy import ForeignKey
from sqlalchemy import or_
from sqlalchemy import and_
from sqlalchemy.orm.session import make_transient
from sqlalchemy.orm import scoped_session
from sqlalchemy.orm import sessionmaker
from sqlalchemy.orm import relation
from sqlalchemy.orm import backref
from sqlalchemy.types import DateTime
from sqlalchemy.orm import column_property
from sqlalchemy.orm import synonym
from sqlalchemy.orm import joinedload
from sqlalchemy.types import Integer
from sqlalchemy.types import Unicode
from sqlalchemy.types import Boolean
from sqlalchemy.types import LargeBinary
from sqlalchemy.types import UnicodeText
from sqlalchemy.sql import func
from sqlalchemy.exc import IntegrityError
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import scoped_session
from sqlalchemy.orm import sessionmaker
from zope.sqlalchemy import ZopeTransactionExtension
from datetime import datetime
from datetime import date
DBSession = scoped_session(sessionmaker(extension=ZopeTransactionExtension()))
DBSession2 = scoped_session(sessionmaker(extension=ZopeTransactionExtension()))
from alpha.modelos import Base


crypt = cryptacular.bcrypt.BCRYPTPasswordManager()

def hash_password(password):
    return unicode(crypt.encode(password))


"""
Tablas de la base de datos
"""

"""
Tablas de asociacion 
"""
class AsociacionRolProyecto(Base):
	__tablename__ = 'asociacion_rol_proyecto'
	left_id = Column(Integer, ForeignKey('rol.id'), primary_key=True)
	right_id = Column(Integer, ForeignKey('proyecto.id'), primary_key=True)
	proyecto= relationship('Proyecto', backref='asociacion_rol_proyecto')


class AsociacionRolFase(Base):
	__tablename__ = 'asociacion_rol_fase'
	left_id = Column(Integer, ForeignKey('rol.id'), primary_key=True)
	right_id = Column(Integer, ForeignKey('fase.id'), primary_key=True)
	fase = relationship('Fase', backref='asociacion_rol_fase')


class AsociacionRolTipoItem(Base):
	__tablename__ = 'asociacion_rol_tipoItem'
	left_id= Column(Integer, ForeignKey('rol.id'), primary_key=True)
	right_id= Column(Integer, ForeignKey('tipoItem.id'), primary_key=True)
	tipoItem= relationship('TipoItem', backref='asociacion_rol_tipoItem')


class AsociacionUsuarioRol(Base):
	__tablename__ = 'asociacion_usuario_rol'
	left_id = Column(Integer, ForeignKey('usuario.id'), primary_key=True)
	right_id = Column(Integer, ForeignKey('rol.id'), primary_key=True)
	rol = relationship('Rol', backref='asociacion_usuario_rol')


class AsociacionRolPermiso(Base):
	__tablename__ = 'asociacion_rol_permiso'
	left_id = Column(Integer, ForeignKey('rol.id'), primary_key=True)
	right_id = Column(Integer, ForeignKey('permiso.id'), primary_key=True)
	tipo= Column(Unicode(50))
	permiso = relationship('Permiso', backref='asociacion_rol_permiso')


class AsociacionFaseTipoItem(Base):
	__tablename__ = 'asociacion_fase_tipo_item'
	left_id = Column(Integer, ForeignKey('fase.id'), primary_key=True)
	right_id = Column(Integer, ForeignKey('tipoItem.id'), primary_key=True)
	tipoItem = relationship('TipoItem', backref='asociacion_fase_tipo_item')

class AsociacionItemArchivo(Base):
	__tablename__ = 'asociacion_item_archivo'
	left_id = Column(Integer, ForeignKey('item.id'), primary_key=True)
	right_id = Column(Integer, ForeignKey('archivo.id'), primary_key=True)
	archivo = relationship('Archivo', backref='asociacion_item_arhivo')

class RelacionSucesor(Base):
	__tablename__ = 'relacion_sucesor'
	left_id = Column(Integer, ForeignKey('item.id'), primary_key=True)
	right_id = Column(Integer, ForeignKey('item.id'), primary_key=True)
	item = relationship('Item', primaryjoin="Item.id==RelacionSucesor.right_id", backref='relacion_sucesor')
	datos= Column(Unicode(50))


class RelacionHijo(Base):
	__tablename__ = 'relacion_hijo'
	left_id = Column(Integer, ForeignKey('item.id'), primary_key=True)
	right_id = Column(Integer, ForeignKey('item.id'), primary_key=True)
	hijo = relationship('Item', primaryjoin="Item.id==RelacionHijo.right_id", backref='relacion_hijo')
	datos= Column(Unicode(50))


class Usuario(Base):
	__tablename__ = 'usuario'
	id = Column(Integer, primary_key=True)
	nombreUsuario = Column(Unicode(50), unique=True)
	_password = Column('password', Unicode(60))
	nombre = Column(Unicode(50))
	apellido = Column(Unicode(50))
	telefono = Column(Integer)
	nroDocumento = Column(Integer)
	fechaCreacion = Column(DateTime, default=datetime.now)
	ultimaSesion= Column(DateTime)
	ultimaSesionFinalizada= Column(DateTime)
	mail = Column(Unicode(50))
	imagen= Column(LargeBinary)
	tipoImagen= Column(Unicode(20))
	nombreImagen= Column(Unicode(50))
	asociacionRol= relationship('AsociacionUsuarioRol', backref='usuario')
	liderProyecto= relationship('Proyecto', backref='usuario')
	liderFase= relationship('Fase', backref='usuario')
	
	def __init__(self, nombreUsuario, password, nombre, apellido, telefono, nroDocumento, mail):
		self.nombreUsuario = nombreUsuario
		self.password = password
		self.nombre = nombre
		self.apellido= apellido
		self.telefono= telefono
		self.nroDocumento= nroDocumento
		self.mail = mail
	
	def _get_password(self):
		return self._password
	
	def _set_password(self, password):
		self._password = hash_password(password)
	
	password = property(_get_password, _set_password)
	password = synonym('_password', descriptor=password)
	
	@classmethod
	def get_by_username(cls, nombreUsuario):
		return DBSession.query(cls).filter(cls.nombreUsuario == nombreUsuario).first()
	
	@classmethod
	def check_password(cls, nombreUsuario, password):
		usuario = cls.get_by_username(nombreUsuario)
		if not usuario:
			return False
		return crypt.check(usuario.password, password)
	
	def getNombreUsuario(self):
		return self.nombreUsuario
	
	def getNombre(self):
		return self.nombre
	
	def getApellido(self):
		return self.apellido
	
	def getTelefono(self):
		return self.telefono
	
	def getNroDocumento(self):
		return self.nroDocumento
	
	def getMail(self):
		return self.mail
	
	def getFecha(self):
		return self.fechaCreacion.strftime("%d-%m-%Y")
	
	def getUltimaSesion(self):
		return self.ultimaSesion.strftime("%d-%m-%Y  %H:%M:%S")
	
	def getUltimaSesionFinalizada(self):
		if self.ultimaSesionFinalizada == None :
			return " "
		else:
			return self.ultimaSesionFinalizada.strftime("%d-%m-%Y  %H:%M:%S")
	
	def getImagen(self):
		return self.imagen
	
	def getTipoImagen(self):
		return self.tipoImagen
	
	def getNombreImagen(self):
		return self.nombreImagen
	
	def esLider(self, instance):
		if instance in self.liderProyecto:
			return True
		else:
			return False
	
	def esLiderFase(self, instance):
		if instance in self.liderFase:
			return True
		else:
			return False
	
	def setNombre(self, nombre):
		self.nombre= nombre
	
	def setNombreUsuario(self, nombreUsuario):
		self.nombreUsuario= nombreUsuario
	
	def setApellido(self, apellido):
		self.apellido= apellido
	
	def setTelefono(self, telefono):
		self.telefono= telefono
	
	def setNroDocumento(self, nroDocumento):
		self.nroDocumento= nroDocumento
	
	def setMail(self, mail):
		self.mail= mail
	
	def setUltimaSesion(self, valor):
		self.ultimaSesion= valor.now()
	
	def setUltimaSesionFinalizada(self, valor):
		self.ultimaSesionFinalizada= valor.now()
	
	def setImagen(self, valor):
		self.imagen= valor
	
	def setTipoImagen(self, valor):
		self.tipoImagen= valor
	
	def setNombreImagen(self, valor):
		self.nombreImagen= valor
    
    asociacion = relationship("AssociationRol", backref="usuario")


class Rol(Base):
	__tablename__ = 'rol'
	id= Column(Integer, autoincrement=True, primary_key=True)
	nombre= Column(Unicode(70), unique=True)
	descripcion= Column(Unicode(100))
	tipo= Column(Unicode(100))
	fechaCreacion= Column(DateTime, default=datetime.now)
	asociacionPermiso= relationship('AsociacionRolPermiso', backref= 'rol')
	asociacionFase= relationship('AsociacionRolFase', backref= 'rol')
	asociacionProyecto= relationship('AsociacionRolProyecto', backref= 'rol')
	asociacionTipoItem= relationship('AsociacionRolTipoItem', backref= 'rol')
	
	def __init__(self, nombreRol,descripcion):
		self.nombre = nombreRol
		self.descripcion = descripcion    
	
	def getNombre(self):
		return self.nombre
	
	def getDescripcion(self):
		return self.descripcion
	
	def getTipo(self):
		return self.tipo
	
	def getFecha(self):
		return self.fechaCreacion
	
	def setNombre(self, nombre):
		self.nombre= nombre
	
	def setDescripcion(self, descripcion):
		self.descripcion= descripcion
	
	def setTipo(self, tipo):
		self.tipo= tipo
	
	def inicializarPermisos(self, session):
		permisos_actuales= []
		permisos_sistema= []
		for relacion in self.asociacionPermiso:
			permisos_actuales.append(relacion.permiso)
		if self.getTipo() == 'Administrador':
			permisos_sistema= session.query(Permiso).filter(Permiso.tipo == 'Administrador').all()
		elif self.getTipo() == 'LiderProyecto':
			permisos_sistema= session.query(Permiso).filter(Permiso.tipo == 'LiderProyecto').all()
		elif self.getTipo() == 'LiderFase':
			permisos_sistema= session.query(Permiso).filter(Permiso.tipo == 'LiderFase').all()
		elif self.getTipo() == 'Desarrollador':
			permisos_sistema= session.query(Permiso).filter(Permiso.tipo == 'Desarrollador').all()
		for permiso in permisos_sistema:
			if not (permiso in permisos_actuales):
				relacion= AsociacionRolPermiso()
				relacion.permiso= permiso
				relacion.left_id= self.id
				self.asociacionPermiso.append(relacion)
		for permiso in permisos_actuales:
			if not (permiso in permisos_sistema):
				for aso in self.asociacionPermiso:
					if aso.permiso == permiso:
						session.delete(aso)
	
	def eliminarPermisos(self, session):
		for relacion in self.asociacionPermiso:
			session.delete(relacion)


class Proyecto(Base):
	__tablename__ = 'proyecto'
	id= Column(Integer, primary_key=True)
	nombre= Column(Unicode(50), unique=True)
	descripcion= Column(Unicode(300))
	fechaCreacion = Column(DateTime, default=datetime.now)
	complejidad= Column(Integer)
	estado= Column(Unicode(20))
	fases = relationship('Fase', backref='proyecto')
	tipoItems = relationship('TipoItem', backref='proyecto')
	lider_id = Column(Integer, ForeignKey('usuario.id'))
	
	def __init__(self, nombre, descripcion):
		self.nombre= nombre
		self.descripcion= descripcion
		self.complejidad= 0
		self.estado= 'No iniciado'
		self.nroFases= 0
	
	def getNombre(self):
		return self.nombre
	
	def getDescripcion(self):
		return self.descripcion
	
	def getFecha(self):
		return self.fechaCreacion.strftime("%d-%m-%Y")
	
	def getComplejidad(self):
		return self.complejidad
	
	def getEstado(self):
		return self.estado
	
	def getNroFases(self):
		return len(self.fases)
	
	def getFases(self):
		return self.fase
	
	def setNombre(self, nombre):
		self.nombre= nombre
	
	def setEstado(self, nuevoEstado):
		self.estado= nuevoEstado
	
	def setDescripcion(self, descripcion):
		self.descripcion= descripcion
	
	def reEnumerarFases(self):
		cont= 0
		for fase in self.fases:
			cont= cont + 1
			fase.setPosicionFase(cont)


class Fase(Base):
	__tablename__ = 'fase'
	id = Column(Integer, primary_key=True)
	posicionFase= Column(Integer)
	nombre= Column(Unicode(50))
	descripcion= Column(Unicode(300))
	nroItems = Column(Integer)
	nroLB = Column(Integer)
	estado = Column(Unicode(20))
	proyecto_id = Column(Integer, ForeignKey('proyecto.id'))
	asociacionTipoItem= relationship('AsociacionFaseTipoItem', backref= 'fase')
	items= relationship('Item', backref= 'fase')
	lineasBase= relationship('LineaBase', backref= 'fase')
	lider_id = Column(Integer, ForeignKey('usuario.id'))
	
	def __init__(self, nombre,descripcion):
		self.nombre= nombre
		self.nroItems= 0
		self.descripcion = descripcion
		self.nroLB = 0
		self.estado = 'Inicial'
	
	def getNombre(self):
		return self.nombre
	
	def getDescripcion(self):
		return self.descripcion
	
	def getPosicionFase(self):
		return self.posicionFase
	
	def getNroItems(self):
		cont= 0
		for item in self.items:
			if item.getEstado() != 'Eliminado':
				cont= cont + 1
		return cont
	
	def getEstado(self):
		return self.estado
	
	def getNroLB(self):
		return len(self.lineasBase)
	
	def setNombre(self, nombre):
		self.nombre= nombre
	
	def setEstado(self, nuevoEstado):
		self.estado= nuevoEstado
	
	def setDescripcion(self, descripcion):
		self.descripcion= descripcion
	
	def setNroLB(self, cantidad):
		self.nroLB= cantidad
	
	def setPosicionFase(self, posicionFase):
		self.posicionFase= posicionFase
	
	def reEnumerarItems(self):
		cont= 0
		#self.items.sort(compara)
		for item in self.items:
			if item.getEstado() != 'Eliminado':
				cont= cont + 1
				item.setNumero(cont)
	
	def reEnumerarLineasBase(self):
		cont= 0
		for aux in self.lineasBase:
			if not aux.estaVacia():
				cont= cont + 1
				aux.setNumero(cont)
	
	def reEnumerarItemsPorTipo(self):
		for relacion in self.asociacionTipoItem:
			cont= 0
			for item in self.items:
				if item.tipoItem == relacion.tipoItem and item.getEstado() != 'Eliminado':
					cont= cont + 1
					item.setNumeroTipoItem(cont)
	
	def actualizarFase(self, session, item, nuevaVersion):
		self.items.sort(compara)
		for aux in self.items:
			print "\n\n"
			print str(aux.id)+ " : "+ str(aux.getNombre())+" : "+ str(aux.getNumero())
			print "\n\n"
		print "\n\n\n\n\n\n"
		indice= self.items.index(item)
		self.items.insert(indice, nuevaVersion)
		for aux in self.items:
			print "\n\n"
			print str(aux.id)+ " : "+str(aux.getNombre()) +" : "+ str(aux.getNumero())
			print "\n\n"
		print "\n\n\n\n\n\n"
		session.add(self)
		self.items.remove(item)
		self.reEnumerarItems()
		self.reEnumerarItemsPorTipo()
		for aux in self.items:
			print "\n\n"
			print str(aux.id)+ " : "+str(aux.getNombre()) +" : "+str(aux.getNumero())
			print "\n\n"
		session.add(self)
	
	def actualizarEstado(self):
		inicial= True
		completo= False
		desarrollo= False
		for item in self.items:
			if item.getEstado() != 'Eliminado':
				completo= True
				if item.getEstado() != 'Bloqueado' :
					desarrollo= True
		if inicial and (not completo) and not(desarrollo):
			self.estado= 'Inicial'
		if inicial and completo and not(desarrollo):
			self.estado= 'Completa'
		if inicial and completo and desarrollo:
			self.estado= 'Desarrollo'
	
	def refrescarLineasBase(self, session):
		for linea in self.lineasBase:
			linea.removerItemsEliminados(session)
		for linea in self.lineasBase:
			linea.removerItemsDesVersionados(session, self)
	
	def autoNombrarLineasBase(self):
		cont= 0
		for linea in self.lineasBase:
			if not linea.estaVacia():
				cont= cont + 1
				linea.setNombre('Linea Base-'+ str(cont))
	
	def eliminarLineasBaseVacias(self, session):
		for linea in self.lineasBase:
			valor= linea.estaVacia()
			if valor:
				print "\n\n\n entrooooo \n\n\n"
				session.delete(linea)
	
	def imprimirLineasBase(self):
		for aux in self.lineasBase:
			print "\n\n"
			print aux.getNombre()
			print "\n"
			aux.imprimirItems()

class TipoItem(Base):
	__tablename__ = 'tipoItem'
	id = Column(Integer, primary_key=True)
	nombre= Column(Unicode(50))
	descripcion= Column(Unicode(50))
	atributos= relationship('Atributo', backref='tipoItem')
	proyecto_id= Column(Integer, ForeignKey('proyecto.id'))
	
	def __init__(self, nombre, descripcion):
		self.nombre= nombre
		self.descripcion= descripcion
	
	def getNombre(self):
		return self.nombre
	
	def getDescripcion(self):
		return self.descripcion
	
	def getNroAtributos(self):
		return len(self.atributos)
	
	def getAtributos(self):
		return self.atributos
	
	def getNroAtributos(self):
		return len(self.atributos)
	
	def setNombre(self, nombre):
		self.nombre= nombre
	
	def setDescripcion(self, descripcion):
		self.descripcion= descripcion
	
	def importarAtributos(self, atributosImportados):
		for atributoImportado in atributosImportados:
			nuevoAtributo= Atributo(atributoImportado.getNombre(), atributoImportado.getTipo())
			nuevoAtributo.setDescripcion(atributoImportado.getDescripcion())
			nuevoAtributo.setValor(atributoImportado.getValor())
			self.atributos.append(nuevoAtributo)


class Item(Base):
	__tablename__ = 'item'
	id = Column(Integer, primary_key=True)
	nombre= Column(Unicode(50))
	numero= Column(Integer)
	numeroTipoItem= Column(Integer)
	version= Column(Integer)
	estado= Column(Unicode(20))
	complejidad= Column(Integer)
	descripcion= Column(Unicode(100))
	marcado= Column(Unicode(20))
	fase_id= Column(Integer, ForeignKey('fase.id'))
	lineaBase_id= Column(Integer, ForeignKey('linea_base.id'))
	"""
	estas dos columnas son para relacionar muchos items con un tipo de item
	"""
	tipoItem_id = Column(Integer, ForeignKey('tipoItem.id'))
	tipoItem = relationship("TipoItem", backref='item')
	"""
	atributos del item
	"""
	atributos= relationship('Atributo', backref='item')
	"""
	para archivos externos
	"""
	relacionArchivo= relationship('AsociacionItemArchivo', backref='item')
	"""
	estas dos columnas son para relaciones de versiones de items
	"""
	versionSuperior_id = Column(Integer, ForeignKey('item.id'))
	versionAnterior = relationship("Item")
	"""
	relacion con el item sucesor
	"""
	relacionSucesor= relationship("RelacionSucesor", primaryjoin=id==RelacionSucesor.left_id, backref='items')
	
	relacionHijo= relationship("RelacionHijo", primaryjoin=id==RelacionHijo.left_id, backref='item')
	
	
	def __init__(self, nombre, complejidad, descripcion):
		self.nombre= nombre
		self.version= 0
		self.complejidad= complejidad
		self.descripcion= descripcion
		self.estado= 'Desaprobado'
		self.marcado= 'No'
	
	def getNombre(self):
		return self.nombre
	
	def getNumero(self):
		return self.numero
	
	def getNumeroTipoItem(self):
		return self.numeroTipoItem
	
	def getVersion(self):
		return self.version
	
	def getEstado(self):
		return self.estado
	
	def getComplejidad(self):
		return self.complejidad
	
	def getDescripcion(self):
		return self.descripcion
	
	def marcarRevision(self):
		self.estado= 'Revision'
	
	def tieneLineaBase(self):
		if self.lineaBase_id != None:
			return True
		else:
			return False
	
	def getLineaBase(self, session):
		lb= session.query(LineaBase).filter_by(id= self.lineaBase_id).first()
		return lb
	
	def tieneVersionAnterior(self):
		if len(self.versionAnterior) > 0:
			return True
		else:
			return False
	
	def getVersionAnterior(self):
		return self.versionAnterior[0]
	
	def tieneVersionSuperior(self):
		if self.versionSuperior_id == None:
			return False
		else:
			return True
	
	def getVersionSuperior(self, session):
		item= session.query(Item).filter_by(id= self.versionSuperior_id).first()
		return item
	
	def getTipoItem(self):
		return self.tipoItem.getNombre()
	
	def getAtributos(self):
		return self.atributos
	
	def tienePadre(self, fase):
		for item in fase.items:
			if item.getEstado() != 'Eliminado' and item != self:
				for relacion in item.relacionHijo:
					if relacion.hijo == self:
						return True
		return False
	
	"""
	note: metodo que devuelve el padre del item, devuelve None en caso de no tener
	"""
	def getPadre(self, fase):
		for item in fase.items:
			if item.getEstado() != 'Eliminado' and item != self:
				for relacion in item.relacionHijo:
					if relacion.hijo == self:
						return item
		return None
	
	"""
	note metodo que pregunta si un item es descendiente de otro en una fase dada
	"""
	def esDescendiente(self, fase, item):
		lista_hijos= self.getGeneraciones(fase, self)
		print "\n\n\n\n\n\n\n"
		for aux in lista_hijos:
			print aux.getNombre()
		print "\n\n\n\n\n\n\n"
		return item in lista_hijos
	
	"""
	note: metodo que acumula los hijos, nietos etc. de un item en una lista incluyendose al item
	"""
	def getGeneraciones(self, fase, item):
		lista= []
		for relacion in item.relacionHijo:
			if relacion.hijo.getEstado() != 'Eliminado' and relacion.hijo in fase.items:
				lista= lista + item.getGeneraciones(fase, relacion.hijo)
		lista = lista + [item]
		return lista
	
	"""
	note: metodo que acumula en una lista los padres, abuelos etc de un item incluyendose a el
	"""
	def getAscendientes(self, fase):
		lista= []
		item_aux= self
		while item_aux.tienePadre(fase):
			lista.append(item_aux.getPadre(fase))
			item_aux= item_aux.getPadre(fase)
		lista = lista + [self]
		return lista
	
	"""
	note: metodo que acumula los sucesores de un item en una lista incluyendose al item, pueden existir repetidos
	"""
	def getSucesores(self, session, fase, item):
		lista= []
		proyecto= session.query(Proyecto).filter_by(id= fase.proyecto_id).first()
		proyecto.fases.sort(comparaFase)
		ubicacion= proyecto.fases.index(fase)
		lista_hijos= item.getGeneraciones(fase, item)
		for aux in lista_hijos:
			for relacion in aux.relacionSucesor:
				fase= proyecto.fases[ubicacion + 1]
				if relacion.item.getEstado() != 'Eliminado' and relacion.item in fase.items:
					lista= lista + item.getSucesores(session, fase, relacion.item)
			lista = lista + [aux]
		return lista
	
	def getAntecesores(self, session, fase, item):
		lista= []
		proyecto= session.query(Proyecto).filter_by(id= fase.proyecto_id).first()
		proyecto.fases.sort(comparaFase)
		ubicacion= proyecto.fases.index(fase)
		lista= item.getAscendientes(fase)
		if ubicacion > 0:
			listaAdd= []
			faseAnterior= proyecto.fases[ubicacion-1]
			for aux in lista:
				for candidato in faseAnterior.items:
					for relacion in candidato.relacionSucesor:
						if relacion.item == aux and candidato.getEstado() != 'Eliminado':
							listaAdd= listaAdd + item.getAntecesores(session, faseAnterior, candidato)
			lista = lista + listaAdd
		return lista
	
	def getSucesoresParaLb(self, session, fase):
		proyecto= session.query(Proyecto).filter_by(id= fase.proyecto_id).first()
		proyecto.fases.sort(comparaFase)
		ubicacion= proyecto.fases.index(fase)
		lista= []
		if ubicacion < (len(proyecto.fases)-1):
			""" note: copia las relaciones que estan en la fase posterior """
			fasePosterior= proyecto.fases[ubicacion+1]
			for relacion in self.relacionSucesor:
				if relacion.item.getEstado() != 'Eliminado' and (relacion.item in fasePosterior.items):
					lista.append(relacion.item)
		return lista
	
	def getAntecesoresParaLb(self, session, fase):
		proyecto= session.query(Proyecto).filter_by(id= fase.proyecto_id).first()
		proyecto.fases.sort(comparaFase)
		ubicacion= proyecto.fases.index(fase)
		lista= []
		if ubicacion > 0:
			""" note: copia las relaciones que estan en la fase anterior """
			faseAnterior= proyecto.fases[ubicacion-1]
			for candidato in faseAnterior.items:
				for relacion in candidato.relacionSucesor:
					if relacion.item == self and candidato.getEstado() != 'Eliminado':
						lista.append(candidato)
		return lista
	
	def getMarcado(self):
		return self.marcado
	
	def setNombre(self, nombre):
		self.nombre= nombre
	
	def setNumero(self, numero):
		self.numero= numero
	
	def setNumeroTipoItem(self, numeroTipoItem):
		self.numeroTipoItem= numeroTipoItem
	
	def setVersion(self, version):
		self.version= version
	
	def setEstado(self, estado):
		self.estado= estado
	
	def setComplejidad(self, complejidad):
		self.complejidad= complejidad
	
	def setDescripcion(self, descripcion):
		self.descripcion= descripcion
	
	def setMarcar(self):
		self.marcado= 'Si'
	
	def setDesMarcar(self):
		self.marcado= 'No'
	
	def getRelacionArchivos(self):
		return self.relacionArchivo
	
	def copiarAtributos(self, atributosImportados, relacionArchivos):
		for atributoImportado in atributosImportados:
			nuevoAtributo= Atributo(atributoImportado.getNombre(), atributoImportado.getTipo())
			nuevoAtributo.setDescripcion(atributoImportado.getDescripcion())
			nuevoAtributo.setValor(atributoImportado.getValor())
			self.atributos.append(nuevoAtributo)
		for relacion in relacionArchivos:
			asociacion= AsociacionItemArchivo()
			archivo= Archivo()
			archivo.setArchivo(relacion.archivo.getArchivo())
			archivo.setTipoArchivo(relacion.archivo.getTipoArchivo())
			archivo.setNombreArchivo(relacion.archivo.getNombreArchivo())
			asociacion.archivo= archivo
			self.relacionArchivo.append(asociacion)
	
	def modificarAtributo(self, atributosImportados, atributo, nombre, descripcion, valor, relacionArchivos):
		for atributoImportado in atributosImportados:
			if atributoImportado != atributo:
				nuevoAtributo= Atributo(atributoImportado.getNombre(), atributoImportado.getTipo())
				nuevoAtributo.setDescripcion(atributoImportado.getDescripcion())
				nuevoAtributo.setValor(atributoImportado.getValor())
				self.atributos.append(nuevoAtributo)
			else:
				nuevoAtributo= Atributo(nombre, atributoImportado.getTipo())
				nuevoAtributo.setDescripcion(descripcion)
				nuevoAtributo.setValor(valor)
				self.atributos.append(nuevoAtributo)
		
		for relacion in relacionArchivos:
			asociacion= AsociacionItemArchivo()
			archivo= Archivo()
			archivo.setArchivo(relacion.archivo.getArchivo())
			archivo.setTipoArchivo(relacion.archivo.getTipoArchivo())
			archivo.setNombreArchivo(relacion.archivo.getNombreArchivo())
			asociacion.archivo= archivo
			self.relacionArchivo.append(asociacion)
	
	def copiarArchivos(self, relacionArchivos):
		for relacion in relacionArchivos:
			asociacion= AsociacionItemArchivo()
			archivo= Archivo()
			archivo.setArchivo(relacion.archivo.getArchivo())
			archivo.setTipoArchivo(relacion.archivo.getTipoArchivo())
			archivo.setNombreArchivo(relacion.archivo.getNombreArchivo())
			asociacion.archivo= archivo
			self.relacionArchivo.append(asociacion)
	
	def inicializarAtributos(self):
		tipoItemElegido= self.tipoItem
		for atributo in tipoItemElegido.atributos:
			nuevoAtributo= Atributo(atributo.getNombre(), atributo.getTipo())
			nuevoAtributo.setValor(atributo.getValor())
			nuevoAtributo.setDescripcion(atributo.getDescripcion())
			self.atributos.append(nuevoAtributo)
	
	def actualizarAtributos(self):
		"""
		note: funcion que al agregar atributos al tipo de item actualiza 
		a todos los items de ese tipo
		"""
		tipoItemElegido= self.tipoItem
		numeroDeAtributosItem= len(self.atributos)
		numeroDeAtributosTipo= len(tipoItemElegido.atributos)
		rango= numeroDeAtributosTipo - numeroDeAtributosItem
		for indice in range(-rango, 0):
			atributo= tipoItemElegido.atributos[indice]
			nuevoAtributo= Atributo(atributo.getNombre(), atributo.getTipo())
			nuevoAtributo.setValor(atributo.getValor())
			nuevoAtributo.setDescripcion(atributo.getDescripcion())
			self.atributos.append(nuevoAtributo)
	
	def copiarRelaciones(self, item, session):
		fase= session.query(Fase).filter_by(id= item.fase_id).first()
		proyecto= session.query(Proyecto).filter_by(id= fase.proyecto_id).first()
		proyecto.fases.sort(comparaFase)
		ubicacion= proyecto.fases.index(fase)
		if ubicacion > 0:
			"""
			note: copia las relaciones que estan en la fase anterior
			"""
			faseAnterior= proyecto.fases[ubicacion-1]
			for candidato in faseAnterior.items:
				for relacion in candidato.relacionSucesor:
					if relacion.item == item and candidato.getEstado() != 'Eliminado':
						asociacion= RelacionSucesor()
						asociacion.item= self
						asociacion.left_id= candidato.id
						candidato.relacionSucesor.append(asociacion)
						session.add(candidato)
		if ubicacion < (len(proyecto.fases)-1):
			"""
			note: copia las relaciones que estan en la fase posterior
			"""
			fasePosterior= proyecto.fases[ubicacion+1]
			for relacion in item.relacionSucesor:
				if relacion.item.getEstado() != 'Eliminado' and (relacion.item in fasePosterior.items):
					asociacion= RelacionSucesor()
					asociacion.item= relacion.item
					asociacion.left_id= self.id
					self.relacionSucesor.append(asociacion)
		"""
		note: copia las relaciones de los padres al nuevo item
		"""
		for candidato in fase.items:
			for relacion in candidato.relacionHijo:
				if relacion.hijo == item and candidato.getEstado() != 'Eliminado':
					asociacion= RelacionHijo()
					asociacion.hijo= self
					asociacion.left_id= candidato.id
					candidato.relacionHijo.append(asociacion)
					session.add(candidato)
		"""
		note: copia las relaciones hijos al nuevo item
		"""
		for relacion in item.relacionHijo:
			if relacion.hijo.getEstado() != 'Eliminado' and (relacion.hijo in fase.items):
				asociacion= RelacionHijo()
				asociacion.hijo= relacion.hijo
				asociacion.left_id= self.id
				self.relacionHijo.append(asociacion)
		return self
	
	def copiarRelacionesParaRevertir(self, item, numeroDeFase, session):
		fase= session.query(Fase).filter_by(id= numeroDeFase).first()
		proyecto= session.query(Proyecto).filter_by(id= fase.proyecto_id).first()
		proyecto.fases.sort(comparaFase)
		ubicacion= proyecto.fases.index(fase)
		if ubicacion > 0:
			"""
			note: copia las relaciones que estan en la fase anterior
			"""
			faseAnterior= proyecto.fases[ubicacion-1]
			for candidato in faseAnterior.items:
				for relacion in candidato.relacionSucesor:
					if relacion.item == item and candidato.getEstado() != 'Eliminado':
						asociacion= RelacionSucesor()
						asociacion.item= self
						asociacion.left_id= candidato.id
						candidato.relacionSucesor.append(asociacion)
						session.add(candidato)
		if ubicacion < (len(proyecto.fases)-1):
			"""
			note: copia las relaciones que estan en la fase posterior
			"""
			fasePosterior= proyecto.fases[ubicacion+1]
			for relacion in item.relacionSucesor:
				if relacion.item.getEstado() != 'Eliminado' and (relacion.item in fasePosterior.items):
					asociacion= RelacionSucesor()
					asociacion.item= relacion.item
					asociacion.left_id= self.id
					self.relacionSucesor.append(asociacion)
		"""
		note: copia las relaciones de los padres al nuevo item
		"""
		for candidato in fase.items:
			for relacion in candidato.relacionHijo:
				if relacion.hijo == item and candidato.getEstado() != 'Eliminado':
					asociacion= RelacionHijo()
					asociacion.hijo= self
					asociacion.left_id= candidato.id
					candidato.relacionHijo.append(asociacion)
					session.add(candidato)
		"""
		note: copia las relaciones hijos al nuevo item
		"""
		for relacion in item.relacionHijo:
			if relacion.hijo.getEstado() != 'Eliminado' and (relacion.hijo in fase.items):
				asociacion= RelacionHijo()
				asociacion.hijo= relacion.hijo
				asociacion.left_id= self.id
				self.relacionHijo.append(asociacion)
		return self

class Rol(Base):

class Atributo(Base):
	__tablename__ = 'atributo'
	id = Column(Integer, primary_key=True)
	nombre= Column(Unicode(50))
	tipo= Column(Unicode(50), nullable=False)
	descripcion= Column(Unicode(100))
	valorString= Column(Unicode(500))
	valorInteger= Column(Integer)
	valorFecha=  Column(DateTime)
	tipoItem_id = Column(Integer, ForeignKey('tipoItem.id'))
	item_id = Column(Integer, ForeignKey('item.id'))
	
	def __init__(self, nombre, tipo):
		self.nombre= nombre
		self.tipo= tipo
	
	def getNombre(self):
		return self.nombre
	
	def getTipo(self):
		return self.tipo
	
	def getValor(self):
		if self.getTipo() == 'String':
			return self.valorString
		elif self.getTipo() == 'Integer':
			return self.valorInteger
		else:
			if self.valorFecha != None:
				return self.valorFecha.strftime("%d-%m-%Y")
			else:
				return 'No existe fecha'
	
	def getDescripcion(self):
		return self.descripcion
	
	def setNombre(self, nombre):
		self.nombre= nombre
	
	def setValor(self, valor):
		if self.getTipo() == 'String':
			self.valorString= valor
		if self.getTipo() == 'Integer':
			self.valorInteger= int(valor)
		if self.getTipo() == 'Date':
			valor= valor.split('-')
			valorDiccionario= {}
			valorDiccionario['anho']= int(valor[2])
			valorDiccionario['mes']= int(valor[1])
			valorDiccionario['dia']= int(valor[0])
			self.valorFecha= date(valorDiccionario['anho'], valorDiccionario['mes'], valorDiccionario['dia'])
	
	def setDescripcion(self, descripcion):
		self.descripcion= descripcion


class Permiso(Base):
	__tablename__ = 'permiso'
	id= Column(Integer, autoincrement=True, primary_key=True)
	nombre = Column(Unicode(70), unique=True)
	descripcion = Column(Unicode(100))
	tipo= Column(Unicode(50))
	
	def __init__(self, nombre, tipo):
		self.nombre = nombre
		self.tipo= tipo
	
	def getNombre(self):
		return self.nombre
	
	def getDescripcion(self):
		return self.descripcion
	
	def getTipo(self):
		return self.tipo
	
	def setNombre(self, nombre):
		self.nombre= nombre
	
	def setDescripcion(self, descripcion):
		self.descripcion= descripcion
	
	def setTipo(self, tipo):
		self.tipo= tipo


class Historial(Base):
	__tablename__ = 'historial'
	id= Column(Integer, autoincrement=True, primary_key=True)
	item_id= Column(Integer, ForeignKey('item.id'))
	item= relationship("Item", uselist=False, backref="historial")
	usuario_id= Column(Integer, ForeignKey('usuario.id'))
	usuario= relationship("Usuario", backref="historial")
	fechaCreacion= Column(DateTime, default=datetime.now)
	descripcion= Column(Unicode(200))

	def __init__(self, descripcion):
		self.descripcion = descripcion
	
	def getItem(self):
		return self.item
	
	def getUsuario(self):
		return self.usuario
	
	def getFecha(self):
		return self.fechaCreacion.strftime("%d-%m-%Y  %H:%M:%S")
	
	def getDescripcion(self):
		return self.descripcion
	
	def setDescripcion(self, descripcion):
		self.descripcion= descripcion
	
	def generarHistorial(self, item, session, request):
		en_linea= authenticated_userid(request)
		usuario= session.query(Usuario).filter_by(nombreUsuario= en_linea).first()
		self.item= item
		self.usuario= usuario
		session.add(self)


class LineaBase(Base):
	__tablename__ = 'linea_base'
	id = Column(Integer, primary_key=True)
	fase_id= Column(Integer, ForeignKey('fase.id'))
	nombre= Column(Unicode(50))
	numero= Column(Integer)
	estado= Column(Unicode(20))
	complejidad= Column(Integer)
	items= relationship('Item', backref= 'LineaBase')
	
	def __init__(self):
		self.estado= 'Cerrada'
	
	def getNombre(self):
		return self.nombre
	
	def getNumero(self):
		return self.numero
	
	def getEstado(self):
		return self.estado
	
	def getComplejidad(self):
		cont= 0
		for item in self.items:
			cont= cont + item.getComplejidad()
		return cont
	
	def getNroItems(self):
		return len(self.items)
	
	def getItems(self):
		lista= []
		for aux in self.items:
			lista.append(aux)
		return lista
	
	def setNombre(self, nombre):
		self.nombre= nombre
	
	def setNumero(self, numero):
		self.numero= numero
	
	def setEstado(self, estado):
		self.estado= estado
	
	def romper(self):
		self.estado= 'Abierta'
		for item in self.items:
			item.setEstado('Revision')
	
	def comprometer(self, session):
		self.estado= 'Comprometida'
		for item in self.items:
			item.setEstado('Revision')
		session.add(self)
	
	def removerItemsEliminados(self, session):
		for item in self.items:
			if item.getEstado() == 'Eliminado':
				self.items.remove(item)
		session.add(self)
	
	def removerItemsDesVersionados(self, session, fase):
		for item in self.items:
			if not (item in fase.items):
				self.items.remove(item)
		session.add(self)
	
	def estaVacia(self):
		lista= []
		cont = 0
		for item in self.items:
			if item != None:
				print str(cont) +' : '+ str(self.getNombre())
				cont = cont + 1
				lista.append(item)
		if lista == []:
			return True
		else:
			return False
	
	def estaEnLineaBase(self, item):
		return item in self.items
	
	def actualizarLineaBase(self, session, item, nuevaVersion):
		#self.items.sort(compara)
		print "\n\n\n\n\n\n"
		for aux in self.items:
			print str(aux.id)+ " : "+ str(aux.getNombre())+" : "+ str(aux.getNumero())
		print "\n\n\n\n\n\n"
		indice= self.items.index(item)
		self.items.insert(indice, nuevaVersion)
		print "\n\n\n\n\n\n"
		for aux in self.items:
			print str(aux.id)+ " : "+str(aux.getNombre()) +" : "+ str(aux.getNumero())
		print "\n\n\n\n\n\n"
		#session.add(self)
		self.items.remove(item)
		#self.reEnumerarItems()
		#self.reEnumerarItemsPorTipo()
		print "\n\n\n\n\n\n"
		for aux in self.items:
			print str(aux.id)+ " : "+str(aux.getNombre()) +" : "+str(aux.getNumero())
		print "\n\n\n\n\n\n"
		session.add(self)
	
	def imprimirItems(self):
		for aux in self.items:
			if aux != None:
				print "\n"
				print aux.getNombre()
				print "\n"
			else:
				print "\n"
				print "Es None..."
				print "\n"

class Archivo(Base):
	__tablename__ = 'archivo'
	id = Column(Integer, primary_key=True)
	valor= Column(LargeBinary)
	tipoArchivo= Column(Unicode(100))
	nombreArchivo= Column(Unicode(100))
	
	def setArchivo(self, valor):
		self.valor= valor
	
	def setTipoArchivo(self, valor):
		self.tipoArchivo= valor
	
	def setNombreArchivo(self, valor):
		self.nombreArchivo= valor
	
	def getArchivo(self):
		return self.valor
	
	def getTipoArchivo(self):
		return self.tipoArchivo
	
	def getNombreArchivo(self):
		return self.nombreArchivo


def compara(x,y):
	return cmp(x.numero, y.numero)


def comparaFase(x,y):
	return cmp(x.posicionFase, y.posicionFase)


def comparaId(x,y):
	return cmp(x.id, y.id)


def eliminar_duplicados(lista):
	refinada= []
	for aux in lista:
		if aux not in refinada:
			refinada.append(aux)
	return refinada


"""
Clase RootFactory para los permisos
"""
class RootFactory(object):
	__acl__ = [ (Allow, Everyone, 'view'),
				(Allow, Authenticated, 'edit') ]
	
	def __init__(self, request):
		pass

